import {BindKeyInfo, ChildProps, ItemAttrs, ParentData, ParentInfo, ResolveData} from './types';
import configure, {Configure} from './configure.ts';
import {DefaultHandlerManger, HandlerManger} from './handler.ts';
import {isArray} from './utils.ts';

/**
 * 解析器
 * @author zj
 * @date 2024/08/22
 */
export interface Resolve {

  resolve(itemAttrs: ItemAttrs | ItemAttrs[], parentInfo: ParentInfo): ResolveData;

  resolveChild(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): ChildProps | undefined;

  resolveChildren(itemAttrs: ItemAttrs[], bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): ChildProps[];

}

export class DefaultResolve implements Resolve {
  protected readonly _configure: Configure;
  protected readonly _handlers: HandlerManger;

  constructor(configure: Configure) {
    this._configure = configure;
    this._handlers = new DefaultHandlerManger();
  }

  resolve(itemAttrs: ItemAttrs | ItemAttrs[], parentInfo: ParentInfo): ResolveData {
    const parentData: ParentData = {
      rowspan: parentInfo.rowspan,
      colspan: parentInfo.colspan,
      size: parentInfo.size
    };
    if (isArray(itemAttrs)) {
      const bindKeys: BindKeyInfo[] = [];
      const children = this.resolveChildren(itemAttrs as ItemAttrs[], bindKeys, parentData, this._configure);
      return {children, bindKeys};
    } else {
      const bindKeys: BindKeyInfo[] = [];
      const children = [];
      const childProps = this.resolveChild(itemAttrs as ItemAttrs, bindKeys, parentData, this._configure);
      if (childProps) {
        children.push(childProps);
      }
      return {children, bindKeys};
    }
  }

  resolveChild(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): ChildProps | undefined {
    if (itemAttrs) {
      const handleData = this._handlers.doHandle(itemAttrs, bindKeys, parentData, configure);
      if (handleData) {
        if (handleData.nextChildProps) {
          if (itemAttrs.children) {
            const nextChildProps = handleData.nextChildProps;
            const nextParentData = handleData.nextParentData;
            nextChildProps.children = this.resolveChildren(itemAttrs.children, bindKeys, nextParentData, configure);
          }
        }
        return handleData.topChildProps;
      }
    }
    return undefined;
  }

  resolveChildren(childrenAttrs: ItemAttrs[], bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): ChildProps[] {
    const children: ChildProps[] = [];
    if (childrenAttrs && childrenAttrs.length > 0) {
      for (let i = 0; i < childrenAttrs.length; i++) {
        const itemProps = this.resolveChild(childrenAttrs[i], bindKeys, parentData, configure);
        if (itemProps) {
          children.push(itemProps);
        }
      }
    }
    return children;
  }

}

export default new DefaultResolve(configure);